package org.gp953.basic.service.impl;

import com.alibaba.fastjson.JSONObject;
import org.gp953.basic.domain.LoginDto;
import org.gp953.basic.exception.BusinessException;
import org.gp953.basic.loginconst.LoginConst;
import org.gp953.basic.service.ILoginService;
import org.gp953.basic.util.*;
import org.gp953.user.domain.LoginInfo;
import org.gp953.user.domain.User;
import org.gp953.user.domain.WeChatUser;
import org.gp953.user.mapper.LoginInfoMapper;
import org.gp953.user.mapper.UserMapper;
import org.gp953.user.mapper.WeChatUserMapper;
import org.gp953.user.verifyconst.VerifyConst;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements ILoginService {

    @Autowired
    private LoginInfoMapper loginInfoMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private WeChatUserMapper weChatUserMapper;

    @Autowired
    private UserMapper userMapper;

    @Override
    public Map<String,Object> accountLogin(LoginDto loginDto) {
        // 前端输入的待验证的账号
        String account = loginDto.getAccount();
        // 前端输入的待验证的密码
        String password = loginDto.getPassword();
        // 校验数据
        if (StringUtils.isEmpty(account)
                || StringUtils.isEmpty(password)) {
            throw new BusinessException("用户名或密码错误！");
        }
        // 验证账号和密码
        LoginInfo loginInfo = loginInfoMapper.queryByAccount(loginDto);
        System.out.println(loginInfo);
        if (loginInfo == null) {
            throw new BusinessException("用户名或密码错误！");
        }

        // 后端通过账户查询出的加密用的盐值
        String salt = loginInfo.getSalt();
        // 后端通过账户查询出的盐值加密后的密码
        String MD5Password = loginInfo.getPassword();
        // 通过把输入密码通过盐值加密后的密码和查询出的密码进行比较判断得出输入密码是否正确
        if (!MD5Password.equals(MD5Utils.encrypByMd5(password + salt))) {
            throw new BusinessException("用户名或密码错误！");
        }
        // 验证通过后UUID生成token
        String token = UUID.randomUUID().toString();
        // redis存储token
        redisTemplate.opsForValue().set(token,loginInfo,30, TimeUnit.MINUTES);
        // 处于数据安全考虑要设置密码为空
        loginInfo.setPassword(null);
        loginInfo.setSalt(null);
        // 返回token到前端
        Map<String,Object> map = new HashMap<>();
        map.put("token",token);
        map.put("loginInfo",loginInfo);
        return map;
    }

    @Override
    public AjaxResult wechatLogin(Map<String, String> map) {
        String code = map.get("code");
        String binderUrl = map.get("binderUrl");
        if (code == null){
            throw new BusinessException("授权码获取失败");
        }
        // 通过code去拿授权用户唯一标识OpenID和接口调用凭证access_token
        String url = LoginConst.GET_ACCESS_TOKEN_URL
                .replace("APPID",LoginConst.APPID)
                .replace("SECRET",LoginConst.SECRET)
                .replace("CODE",code);
        String accessTokenUrl = HttpClientUtils.httpGet(url);
        System.out.println(accessTokenUrl);
        JSONObject jsonObject = JSONObject.parseObject(accessTokenUrl);
        String accessToken = jsonObject.getString("access_token");
        String openId = jsonObject.getString("openid");

        // 通过openId去查看t_wxuser表中是否已经微信授权登录过了如果是，就直接免密登录
        WeChatUser weChatUser = weChatUserMapper.queryByOpenId(openId);
        if (weChatUser!=null) {//直接免密登录
            Long userId = weChatUser.getUser_id();
            LoginInfo loginInfo = loginInfoMapper.queryByUserId(userId);
            // 验证通过后UUID生成token
            String token = UUID.randomUUID().toString();
            // redis存储token
            redisTemplate.opsForValue().set(token,loginInfo,30, TimeUnit.MINUTES);
            // 处于数据安全考虑要设置密码为空
            loginInfo.setPassword(null);
            loginInfo.setSalt(null);
            // 返回token到前端
            Map<String,Object> resultMap = new HashMap<>();
            resultMap.put("token",token);
            resultMap.put("loginInfo",loginInfo);
            System.out.println(1111111);
            return AjaxResult.me().setResultObj(resultMap);
        } else {//没有授权过，这要用户绑定信息
            binderUrl = binderUrl + "?accessToken="+ accessToken + "&openId=" + openId;
            return AjaxResult.me().setResultObj(binderUrl).setSuccess(false);
        }
    }

    @Override
    public Map<String, Object> binder(Map<String, String> map) {

        String accessToken = map.get("accessToken");
        String openId = map.get("openId");
        String verifyCodeTemp = map.get("verifyCode");
        String phone = map.get("phone");

        if (StringUtils.isEmpty(accessToken)
                || StringUtils.isEmpty(openId)
                || StringUtils.isEmpty(verifyCodeTemp)
                || StringUtils.isEmpty(phone)) {
            throw new BusinessException("手机号和验证码不能为空");
        }

        // 获取验证码查看验证码是否过期
        Object verifycodeAndTimestamp = redisTemplate.opsForValue().get(VerifyConst.BUSINESS_REGISTER_PREFIX + phone);

        if (verifycodeAndTimestamp == null) { // 过期了就报错让用户重新获取
            throw  new BusinessException("验证码已过期，请重新获取");
        }
        // 没过期就验证验证码是否一致
        String verifyCode = verifycodeAndTimestamp.toString().split(":")[0];
        if (!verifyCode.equalsIgnoreCase(verifyCodeTemp)) {
            throw new BusinessException("验证码错误，请重新输入");
        }


        // 通过openId和accessToken拿到用户个人信息
        String getUserInfoUrl = LoginConst.GET_USERINFO_URL
                .replace("ACCESS_TOKEN",accessToken)
                .replace("OPENID",openId);
        String userInfoUrl = HttpClientUtils.httpGet(getUserInfoUrl);
        JSONObject userInfo = JSONObject.parseObject(userInfoUrl);
        WeChatUser weChatUser = initWeChatUser(userInfo);
        String nikcname = weChatUser.getNickname();

        // 校验手机号是否被注册了，注册了就直接生成t_wxuser表中的数据并相互绑定即可
        User userTemp = userMapper.queryByPhone(phone);
        User user = new User();
        LoginInfo loginInfo = new LoginInfo();
        if (userTemp != null) {
            user = userTemp;
            // 获取一个loginInfo用于返给前端做回显
            loginInfo = loginInfoMapper.queryByUserId(user.getId());
        } else { // 一个新的user用来绑定
            user = initUser(phone,nikcname);
            loginInfo = User2LoginInfo(user);
            loginInfoMapper.save(loginInfo);
            Long loginInfoId = loginInfo.getId();
            user.setLogininfo_id(loginInfoId);
            userMapper.save(user);
        }

        weChatUser.setUser_id(user.getId());
        weChatUserMapper.save(weChatUser);

        // 免密登录
        // 验证通过后UUID生成token
        String token = UUID.randomUUID().toString();
        // redis存储token
        redisTemplate.opsForValue().set(token,loginInfo,30, TimeUnit.MINUTES);
        // 处于数据安全考虑要设置密码为空
        loginInfo.setPassword(null);
        loginInfo.setSalt(null);
        // 返回token到前端
        Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("token",token);
        resultMap.put("loginInfo",loginInfo);

        return resultMap;
    }


    private User initUser(String phone, String nikcname) {
        User user = new User();
        user.setUsername(nikcname);
        user.setPhone(phone);
        String salt = StrUtils.getComplexRandomString(32);
        user.setSalt(salt);
        String password = StrUtils.getComplexRandomString(6);
        /*// 发送用户名密码短信到用户手机
        String message = "绑定微信成功！您也可以通过账号名："
                + nikcname + "或手机号通过密码："
                + password + "登录";
        TextingUtil.send(phone,message);*/
        user.setPassword(MD5Utils.encrypByMd5(password+salt));
        return user;
    }

    private WeChatUser initWeChatUser(JSONObject userInfo) {
        WeChatUser weChatUser = new WeChatUser();
        weChatUser.setAddress(null);
        weChatUser.setHeadimgurl(userInfo.getString("headimgurl"));
        weChatUser.setOpenid(userInfo.getString("openid"));
        weChatUser.setNickname(userInfo.getString("nickname"));
        weChatUser.setUnionid(userInfo.getString("unionid"));
        weChatUser.setSex(userInfo.getInteger("sex"));
        weChatUser.setOpenid(userInfo.getString("openid"));

        return weChatUser;
    }

    private LoginInfo User2LoginInfo(User user) {
        LoginInfo loginInfo = new LoginInfo();
        BeanUtils.copyProperties(user,loginInfo);
        loginInfo.setType(1);// 主站用户设置type为1
        return loginInfo;
    }
}
